package view

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import ext.toRad
import kotlin.math.cos
import kotlin.math.sin

class TempValueMeter : View {
    companion object {
        private const val STEPS = 10
        private const val START_ANGLE = 315f
        private const val END_ANGLE = 45f
        private const val THINKNESS_P = 0.3f
        private const val STEP_COLOR = Color.BLACK
        private const val MARGIN_COLOR = 0xffffbb33.toInt()
        private const val NUMBER_COLOR = Color.BLACK
        private const val POINT_COLOR = Color.RED
        private const val POINT_CIRCLE_COLOR = Color.GRAY
        private const val TEXT_COLOR = Color.BLACK
        private const val POINT_ANGLE = 70f
        private const val POINT_LENGTHP = 0.3f
    }

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    var maxValue: Float = 300f
        set(value) {
            if (field != value) {
                field = value
                invalidate()
            }
        }

    var minValue: Float = 0f
        set(value) {
            if (field != value) {
                field = value
                invalidate()
            }
        }

    var currentValue: Float = 50f
        set(value) {
            if (field != value) {
                field = value
                invalidate()
            }
        }

    private var width: Float = 0f
    private var height: Float = 0f

    private fun r(): Float {
        val wa = width / 2
        val ha = height * 1.414f / (1 + 1.414f)
        val a = if (wa < ha) wa else ha
        return a / (1 + 0.5f * THINKNESS_P)
    }

    private fun margin(): Float {
        val r = r()
        return r - r * 0.5f * THINKNESS_P
    }

    private fun drawSteps(canvas: Canvas) {
        canvas.rotate(END_ANGLE)
        val l = margin()
        val gap = -(START_ANGLE - END_ANGLE) / (STEPS - 1)
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.color = STEP_COLOR
        paint.strokeWidth = 10f
        paint.style = Paint.Style.STROKE
        for (i in 0 until STEPS) {
            canvas.drawLine(l, 0f, 0.85f * l, 0f, paint)
            canvas.rotate(gap)
        }
    }

    private fun drawMargin(canvas: Canvas, x0: Float, y0: Float) {
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        val r = r()
        paint.color = MARGIN_COLOR
        paint.style = Paint.Style.STROKE
        paint.strokeCap = Paint.Cap.ROUND
        paint.strokeWidth = r * THINKNESS_P
        val rectF = RectF(x0 - r, y0 - r, x0 + r, y0 + r)
        canvas.drawArc(rectF, START_ANGLE - 180, START_ANGLE - END_ANGLE, false, paint)
    }

    private fun drawNumber(canvas: Canvas, x0: Float, y0: Float) {
        val r = r()
        val start = START_ANGLE - 90
        val end = END_ANGLE - 90
        val k = (minValue - maxValue) / (start - end)
        val b = minValue - k * start
        var angle = start
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        val gap = (START_ANGLE - END_ANGLE) / (STEPS - 1)
        val measure = paint.fontMetrics
        val offset = (measure.top + measure.bottom) / 2
        paint.color = NUMBER_COLOR
        paint.textSize = 20f
        paint.textAlign = Paint.Align.CENTER
        for (i in 0 until STEPS) {
            val pangle = angle * Math.PI.toFloat() / 180
            val y = y0 - (sin(pangle) * r + offset)
            val x = x0 + (cos(pangle) * r)
            val num = (k * angle + b).toInt().toString()
            canvas.drawText(num, x, y, paint)
            angle -= gap
        }
    }

    private fun drawPoint(canvas: Canvas, x0: Float, y0: Float) {
        val r = margin() * POINT_LENGTHP
        val start = START_ANGLE - 90
        val end = END_ANGLE - 90
        val k = (start - end) / (minValue - maxValue)
        val b = start - k * minValue
        val angle = currentValue * k + b
        canvas.save()
        canvas.translate(x0, y0)
        val angle1 = angle - POINT_ANGLE / 2
        val angle2 = angle + POINT_ANGLE / 2
        val p1 = PointF(0f, 0f)
        val p2 = PointF(r * cos(angle1.toRad()), -r * sin(angle1.toRad()))
        val p3 = PointF(2 * r * cos(angle.toRad()), -2 * r * sin(angle.toRad()))
        val p4 = PointF(r * cos(angle2.toRad()), -r * sin(angle2.toRad()))
        val path = Path()
        path.reset()
        path.moveTo(p1.x, p1.y)
        path.lineTo(p2.x, p2.y)
        path.lineTo(p3.x, p3.y)
        path.lineTo(p4.x, p4.y)
        path.close()
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.color = POINT_COLOR
        paint.style = Paint.Style.FILL
        canvas.drawPath(path, paint)

        paint.color = POINT_CIRCLE_COLOR
        canvas.drawCircle(0f, 0f, r, paint)

        paint.textAlign = Paint.Align.CENTER
        paint.style = Paint.Style.STROKE
        paint.textSize = 20f
        paint.color = TEXT_COLOR
        val s = "${currentValue.toInt()}℃"
        val y = r * 2
        canvas.drawText(s, 0f, y, paint)

        canvas.restore()
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        width = w.toFloat()
        height = h.toFloat()
    }

    override fun onDraw(canvas: Canvas) {
        val x0 = width / 2
        val y0 = height * 1.414f / (1 + 1.414f)

        canvas.save()
        canvas.translate(x0, y0)
        drawSteps(canvas)
        canvas.restore()
        drawMargin(canvas, x0, y0)
        drawNumber(canvas, x0, y0)
        drawPoint(canvas, x0, y0)
    }
}